// 7.文件和流
/**
 * 1. C++进行文件处理
 *       必须在C++源代码文件中包含头文件<iostream>和<fstream>
 * 2. 三个相关数据类型
 *        ofstream
 *            输出文件流，向文件写入信息，也可以创建文件
 *        ifstream
 *            输入文件流，从文件读取信息
 *        fstream
 *            文件流，读写文件，可以创建文件
 * 3. 打开文件
 *        读写文件前必须打开文件
 *        语法 obj.open(const char* filename,ios::openmode mode);
 *        说明：
 *            obj是 fstream、ofstream、ifstream对象
 *            第二个参数定义文件被打开的模式
 *                 std::ios::app    追加模式。所有写入都追加到文件末尾。
 *                 std::ios::ate    文件打开后定位到文件末尾
 *                 std::ios::out    打开文件用于写入
 *                 std::ios::in     打开文件用于读取
 *                 std::ios::truc   如果该文件已经存在，其内容将在打开文件前被截断，即文件长度设为0
 *                
 * 3. 关闭文件
 *        obj.close();
 * 4. 文件位置指针
 *        obj.seekg(n,ios::beg|ios::cur|ios::end)
 *        obj.seekp(n,ios::beg|ios::cur|ios::end)
 *        说明：第一个参数通常是一个长整型，第二个参数可以指定查找方向。beg （默认） 从流的开始方向定位，cur 从当前位置开始定位，end 从流的末尾开始定位
 *        注意: ifstream obj调seekg ,ofstream obj 调seekp, fstream 两个都可以调
 * 
 * 
 * 扩展(xx1  以1结尾)：
 * 1. #111文件路径
 *      绝对路径
 *          从盘符开始的全部路径 如：C:\\xx\\xx\\xx\\a.txt
 *      相对路径 
 *          从项目工程目录出发 如：./xx/xx.a  ../ss/xx.a
 *          ./   表示项目工程目录，可省略
 *          ..// 表示项目工程目录的上级目录
 *      /和\基本没区别，主要\是转义字符，写成\\；/ \\ // \\\\ 都是可以的。通常用反斜杠'\'表示绝对路径，用正斜杠'/'表示相对路径
 *      
 *      R("xx\xx\b.txt") R字符串不会转义，这样也可只写\,当然\\也是允许的，跟//一样。
 * 
 * 2. C/C++中的标准泛空格符有哪些
 *      '  '	(0x20)	space (SPC)             空格
 *      '\t'	(0x09)	horizontal tab (TAB)    水平制表符
 *      '\n'	(0x0a)	newline (LF)            换行符
 *      '\v'	(0x0b)	vertical tab (VT)       垂直制表符
 *      '\f'	(0x0c)	feed (FF)               
 *      '\r'	(0x0d)	carriage return (CR)
 * 3. 文件输入流遇到空白符截止
 * 4. C++缓存区概念
 *      全缓冲   磁盘文件的读写,ofstream
 *      行缓冲   键盘输入数据，getchar()
 *      不带缓冲 std::cerr
 * 4. cin.ignore cin.getline
 *     cin方法:
 *        cin.get()、cin.getline、cin.peek()、cin.eof()、cin.putback()、cin.ignore()、
 * 
 *    cin>>与cin.get()/cin.getline()的区别
 *          输出类型，是否可输出空白符
 *    cin.get()和cin.getline的区别
 *          二次使用，指针位置
 *    cout方法:
 *        cout.put()
 *  
 *    其他:
 *        get()、getchar()、put()、putchar()
 *        getline()
 *            类似于：cin.getline
 * 
 * 疑问；
 *  1. fstream obj.open("xx",std::ios::trunc | std::ios::out) 
 *   trunc 必须和out一起使用，不然终止程序。ifstream和ofstream obj不会这样。
 *    当openmode与流操作符（<< >>）不一致时，不会报错，只是不生效。
 *  2. fstream obj.seekp 和obj.seekg交替使用会异常（不报错）。要么用就用一个，那我就想交替用呢？
 * 
 * 
 * 
*/
#include <iostream>
#include <fstream>
#include <string.h>

#define __mark 111

#if 111 == __mark

/**
 * #111 文件路径
*/
int main(void)
{
  std::fstream fs;
  std::ifstream ifs;
  std::ofstream ofs;
  /**
   * 1. 绝对路径
   * 绝对路径就是从根目录开始一直到文件名
   * C:\\study\\xxx.txt c盘下study文件夹下xxx.txt文件
   * 要\\,转义字符的原因；也可以使用R"(xxxx)"
  */
  fs.open("E:\\CodeField\\Code_Cpp\\C_Single\\study\\day22\\review\\src\\a.dat", std::ios::in | std::ios::out | std::ios::trunc);
  // fs.open("E:/CodeField/Code_Cpp/C_Single/study/day22/review/src/a.dat", std::ios::in | std::ios::out | std::ios::trunc);
  // fs.open("E://CodeField//Code_Cpp//C_Single//study//day22//review//src//a.dat", std::ios::in | std::ios::out | std::ios::trunc);
  // fs.open(R"(E:\\CodeField\\Code_Cpp\\C_Single\\study\\day22\\review\\src\\a.dat)", std::ios::trunc | std::ios::out);

  // ifs.open("E:\\CodeField\\Code_Cpp\\C_Single\\study\\day22\\review\\src\\a.dat", std::ios::in | std::ios::trunc);
  // ifs.open("E:\\CodeField\\Code_Cpp\\C_Single\\study\\day22\\review\\src\\a.dat", std::ios::in | std::ios::trunc);

  /*
      * 2. 相对路径
      * ./  工程目录同级，（./ 可省略）
      * ../ 工程目录上一级
      */

  // fs.open("a.dat", std::ios::in | std::ios::out | std::ios::trunc); // 跑到工作目录下

  // fs.open(".\\a.dat", std::ios::in | std::ios::out | std::ios::trunc);

  // fs.open("..//C_SINGLE//a.dat", std::ios::in | std::ios::out | std::ios::trunc); // 跑到工程目录上级，在回来找它下面的a.dat

  if (!fs)
  {
    std::cerr << "打开文件失败!" << std::endl;
    exit(-1);
  }
  std::cout << "请输入一段内容：";
  char str[100];
  std::cin >> str;
  // std::cin.ignore();
  std::cout << "str : " << str << std::endl;
  // std::cout << "str : " << str << std::endl;
  fs << str;
  // fs.flush();
  // fs.close();
  // fs.open(R"(E:\CodeField\Code_Cpp\C_Single\study\day22\review\src\a.dat)", std::ios::in);

  strcpy(str, ""); // 清空str
  fs.seekg(0, std::ios::beg);
  fs >> str;
  std::cout << "输出的内容如下: " << std::endl
            << str << std::endl;

  std::cout << "请再输入一段内容：";
  std::cin >> str;
  std::cout << "str : " << str << std::endl;
  // std::cin.ignore();
  // fs.flush();
  // fs.seekp(0, std::ios::end);
  fs.seekg(0, std::ios::end);
  fs << str;
  strcpy(str, "");
  fs.seekg(0, std::ios::beg);
  fs >> str;
  std::cout << "输出的内容如下: " << std::endl
            << str << std::endl;
  fs.close();
  printf("-----------end-------------\n");
  return 0;
}
#elif 2 == __mark
int main(void)
{

  printf("-----------end-------------\n");
  return 0;
}
#endif